package com.ws.webpacket.internet;


import com.google.gson.Gson;
import com.ws.webpacket.util.HLog;

import java.io.IOException;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

/**
 *  封装网络请求
 *
 */
public abstract class HttpRequest<T> {

    private static final int CONNECT_TIME_OUT = 30;
    private static final int READ_TIME_OUT = 30;
    private static final int WRITE_TIME_OUT = 30;

    private boolean isGet  = true;

    private static OkHttpClient client;
    protected static Gson gson;

    /**
     * 开始网络请求
     */
    public void startRequest(Parameter parameter){
        init(parameter);
        requestOption(parameter);
    }

    /**
     *  当需要统一对数据做操作时的操作
     */
    protected void init(Parameter parameter){

    }

    /**
     * 具体的网络请求
     */
    private void requestOption(Parameter parameter){
        Observable.just(parameter)
                .subscribeOn(Schedulers.io())
                .map(new Func1<Parameter,T>(){
                    @Override
                    public T call(Parameter parameter) {
                        Response response = requestHttp(parameter);
                        if (gson == null)
                            gson = new Gson();
                        T t = null;
                        try {
                            t = decodeResult(response.body().string());
                        } catch (Exception e) {
                            return null;
                        }
                        return t;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<T>() {
                    @Override
                    public void call(T httpResult) {
                        if(httpResult == null){
                            error("解析错误");
                        }else{
                            result(httpResult);
                        }
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        error(throwable.getMessage());
                    }
                });
    }

    //网络请求
    public Response requestHttp(Parameter parameter){

        if(client == null)
            client  = new OkHttpClient.Builder()
                    .connectTimeout(CONNECT_TIME_OUT, TimeUnit.SECONDS)
                    .readTimeout(READ_TIME_OUT,TimeUnit.SECONDS)
                    .writeTimeout(WRITE_TIME_OUT,TimeUnit.SECONDS)
                    .build();

        Request.Builder builder = new Request.Builder();
        builder.url(parameter.getUrl());
        if(isGet){
            builder.get();
        }else{
            builder.post(parameter.getRequestBody());
        }
        Request request = builder.build();


        Call call =  client.newCall(request);
        Response response  = null;
        try {
            response =call.execute();
        } catch (IOException e) {

            return null;
        }

        return response;

    }

    //解码数据
    public abstract T decodeResult(String json) throws Exception;

    //解析成功返回数据
    public abstract void result(T result);

    //出现异常时的处理
    public abstract void error(String msg);


    /**
     * 参数构建与获取工具类
     */
    class Parameter {
        private HashMap<String,String> map;

        private static final String URL = "url";

        private static final String METHOD = "method";
        private static final String GET = "get";
        private static final String POST = "post";

        public Parameter(){
            map = new HashMap<>();
        }

        public Parameter setUrl(String url){
            map.put(URL,url);
            return this;
        }

        public Parameter methodGet(){
            map.put(METHOD,GET);
            return this;
        }

        public Parameter methodPost(){
            map.put(METHOD,POST);
            return this;
        }

        public Parameter addValue(String key,String value){
            map.put(key,value);
            return this;
        }

        public String getUrl(){
            String url = map.get(URL);
            if(map.get(METHOD).equals(GET)){
                Set<String> keySet =  map.keySet();
                int index = 0;
                for (String key:keySet) {
                    if(index == 0){
                        url += "?";
                    }
                    if(!map.get(key).equals(GET)&&!map.get(key).equals(POST)){
                        url += "&"+key+"="+map.get(key);
                    }
                    index++;
                }
            }
            return url;
        }

        public boolean isGet(){
            if(map.get(METHOD).equals(POST)){
                return false;
            }
            return true;
        }


        public RequestBody getRequestBody(){
            if(map.get(METHOD).equals(POST)){
                Set<String> keySet =  map.keySet();
                FormBody.Builder builder =new FormBody.Builder();
                for (String key:keySet) {
                    if(!map.get(key).equals(GET)&&!map.get(key).equals(POST)){
                        builder.add(key,map.get(key));
                    }
                }
                return builder.build();
            }
            return null;
        }

    }

}
